/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

 /***************************************************************************
 * Name: ipc_endpoint_client.cpp
 *
 * Purpose: implementation a client endpoint with ipc
 *
 * Developer:
 *   wen.gu , 2021-10-12
 *
 * TODO:
 *
 ***************************************************************************/

 /******************************************************************************
 **    INCLUDES
 ******************************************************************************/
#include "icpp/com/endpoint.h"
#include "ipc_endpoint_client.h"

#define LOG_TAG "ipec"
#include "icpp/core/log.h"

namespace icpp
{
namespace com
{
/******************************************************************************
 **    MACROS
 ******************************************************************************/
#define IPC_CLIENT_COMP_NAME "ipc_endpoint_client"
#define IPC_CLIENT_COMP_VER  "0.0.1"

#define IPC_CLIENT_AUTO_RECONNECT true
#define IPC_CLIENT_NOT_RECONNECT false

#define SOCKET_ID_NOT_CONNECT (-2)

/******************************************************************************
 **    VARIABLE DEFINITIONS
 ******************************************************************************/


/******************************************************************************
 **    FUNCTION DEFINITIONS
 ******************************************************************************/
IpcEndpointClient::IpcEndpointClient(const std::string& url)
    :Endpoint(IPC_CLIENT_COMP_NAME, IPC_CLIENT_COMP_VER),
    srv_url_(url),
    ipc_client_(url, IPC_CLIENT_AUTO_RECONNECT)
{
    /** todo something */
}

IpcEndpointClient::~IpcEndpointClient()
{
    /** todo something */
}

/**initialize endpoint. 
 * if role service, then  do  communication protocol bind(e.g. socket bind)
 * if role client, then try to connect to service endpoint
 */
core::IcppErrc IpcEndpointClient::start() 
{
    return ipc_client_.start([this](int socket_id, bool is_connected)  /** OnConnectHandler */
    {
        if (this->on_connect_state_change_)
        {
            this->on_connect_state_change_((EndpointId)socket_id, is_connected);
        }
      //  socket_client_id_ = is_connected ? socket_id : SOCKET_ID_NOT_CONNECT;
    },
    [this](const uint8_t* buf, uint32_t len) /** OnReceiveHandler */
    {
        if (on_packet_parse_)
        {
            on_packet_parse_->fillData(buf, len);
        }
    });
}

/** uninitialize endpoint
 * if role service, then do unbind
 * if role client,  then disconect from service endpoint
*/
core::IcppErrc IpcEndpointClient::stop() 
{
    return ipc_client_.stop();
}

/** the common api */
/**
 * endpoint_id:   == INVALID_ENDPOINT_ID:   (default)broadcast to all endpoints which connected with current endpoint, 
 *                != INVALID_ENDPOINT_ID: send to a special endpoint  which connected with current endpoint
 */
core::IcppErrc IpcEndpointClient::send(Message::MessagePtr msg_ptr)
{
    PayloadPtr payload_ptr = IpcPacketBuilder::MakeIpcPacket(msg_ptr);
    if (!payload_ptr)
    {
        return core::IcppErrc::BadParameter;
    }

    return ipc_client_.send(payload_ptr->data(), payload_ptr->size());
}

void IpcEndpointClient::setReceiveHandler(ReceiveHandler handler)
{
    /** todo, refine me?? */
    on_packet_parse_ = std::make_shared<IpcPacketParser>(handler);
}

void IpcEndpointClient::setConnectionStateHandler(ConnectionStateHandler handler) 
{
    on_connect_state_change_ = handler;
}

void IpcEndpointClient::setEndpointIdAllocator(EndpointIdAllocator handler) 
{
    on_endpoint_id_allocator_ = handler;
}

EndpointRole IpcEndpointClient::role() const 
{
    return EndpointRole::kClient;
}

const std::string& IpcEndpointClient::url() const  
{
    return srv_url_;
}


} /** namespace com */
} /** namespace icpp */
